﻿/*!
 * # 模块 JS:
 *  Outbox - 已发送的通知
 * 
 * # 描述:
 *  提供发送新通知，删除通知，以及对所有已经发送通知的访问和操作。可以由最终用户或业务系统使用。
 * 
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

/*
 * @param {Object} $    jQuery 命名空间。
 * @param {Object} $$   pittypat 命名空间。
 * @param {Object} _mod 模块 Apps (应用与功能) 的命名空间。
 * 
 * 使用 pittypat.namespace('...') 以确保 _mod 命名空间是存在的。
 * 
 * 更多说明请参见：
 * https://www.pittypat.work/com/waln/pittypat/coding/help/index.html#js。
 */
(function ($, $$, _mod) {
    'use strict';

    $$.ui.msg = '...';
    /*
     * 为登录用户注册一个处理函数。
     * 由于没有为匿名用户注册处理函数，那么当发现用户尚未登录时，则会默认跳转到首页（登录页）。
     * 
     * 如果需要为匿名用户添加处理逻辑，应该使用如下格式的代码：
     * $$({
     *     authorized: function (_) {
     *         ...
     *     },
     *     anonymous: function (_) {
     *         // 跳转到自定义的登录页面
     *         window.location = '../../../../login.html';
     *     }
     * });
     * 
     * 如果需要自定义登录页面，则可能还需要添加 init 等处理函数。详细帮助请参见：
     * https://www.pittypat.work/com/waln/pittypat/ref/help/pittypat.js.html#pittypat。
     *
     * 参数 _ 的定义如下：
     * {
     *    user:  {Object},  // (只读)当前用户的用户信息
     *    app:   {Object},  // (只读)当前应用的命名空间，如果无法定位，则为 null
     *    mod:   {Object},  // (只读)当前模块的命名空间，如果无法定位，则为 null
     *    init:  {Boolean}, // (只读)是否正在初始化页面
     *    first: {Boolean}, // (只读)是否首次执行 authorized
     *    data:  {any}      // (读写)前述的 data 数据，或 data 函数返回的结果
     * }
     */
    $$(function (_) {
        var
            // 模块 UI 命名空间
            _ui = _mod.ui = _mod.ui || {},
            // 模块 API 命名空间
            _api = _mod.api,
            // 主工作区
            $main = $('.pt-main'),
            // 通知列表
            $notifications = $('#notifications'),
            // 置顶通知列表
            $topNotifications = $('#top-notifications');

        if (_.init) {
            // 检查指定的图片是否加载成功
            function imgOk(img) {
                if (!img.complete) {
                    return false;
                }

                if (typeof img.naturalWidth != "undefined" && img.naturalWidth == 0) {
                    return false;
                }

                return true;
            }

            // 在当前已经加载行数的基础上增加指定的行数
            function setLoadedSummary() {
                if (arguments.length < 1) {
                    return;
                }

                // 总行数和已加载行数
                var $loadedRows = $('#loaded-rows'),
                    $totalRows = $('#total-rows'),
                    totalRows = 0,
                    loadedRows = Long.fromString($loadedRows.text() || '0').add(arguments[0]);

                if (arguments.length == 1) {
                    // 此时认为只有提供了一个增量
                    totalRows = Long.fromString($totalRows.text() || '0').add(arguments[0]);
                } else {
                    // 第二个参数
                    totalRows = Long.fromValue(arguments[1]);
                }

                $loadedRows.text(loadedRows);
                $totalRows.text(totalRows);

                // 如果已经加载的行数等于或超过了总行数，隐藏加载更多按钮
                $('#load-more').css('display', loadedRows.gte(totalRows) ? 'none' : 'flex');
            }

            const URGENCY_ICONS = ['', 'star_border', 'star_half', '', 'star'],
                URGENCY_NAMES = ['', '普通', '紧急', '', '特急'];

            /*
             * User 结构如下：
             * {
             * }
             */
            _ui.notification = {
                /*
                 * User 对象对应的 DOM HTML。
                 */
                get html() {
                    return '<article class="pt-row pt-model model-notification">' +
                        '    <hr />' +
                        '    <header class="hover">' +
                        '        <div class="pt-row-icon">' +
                        '            <img class="model-notification-sender-face big" src="" alt="" />' +
                        '        </div>' +
                        '        <div class="pt-row-info">' +
                        '            <div>' +
                        '                <span class="pt-model-prop model-notification-ut">' +
                        '                    <i class="material-icons model-notification-urgency">star_border</i>' +
                        '                    <span class="model-notification-title"></span>' +
                        '                </span>' +
                        '                <span class="pt-model-prop model-notification-summary theme-text-2 hidden-phone hidden-tablet"></span>' +
                        '            </div>' +
                        '            <div class="w-5 hidden-phone">' +
                        '                <span class="pt-model-prop model-notification-group"></span>' +
                        '            </div>' +
                        '            <div class="w-12 hidden-phone"">' +
                        '                <span class="pt-model-prop model-notification-sender-name"></span>' +
                        '            </div>' +
                        '            <div class="w-9"">' +
                        '                <span class="pt-model-prop model-notification-receive-time"></span>' +
                        '            </div>' +
                        '        </div>' +
                        '        <div class="pt-row-more">' +
                        '            <button data-target-menu="#model-notification-menu" class="mdc-ripple-surface mdc-ripple-surface--primary" data-target-dialog="#set-position-dialog" data-mdc-ripple-is-unbounded data-mdc-auto-init="MDCRipple">' +
                        '                <i class="material-icons">more_vert</i>' +
                        '            </button>' +
                        '        </div>' +
                        '    </header>' +
                        '</article>';
                },

                /*
                 * 将指定的 App 对象添加到指定 DOM 列表的指定位置。
                 * 
                 * @param {any}    args   _api.list 的 args 事件创建的参数。
                 * @param {Object} model  一个 App 对象。
                 * @param {Number} pos    插入位置，非数字将清空现有列表，小于 0 将添加到最后。
                 * @param {jQuery} $list  要插入的 DOM 列表。
                 */
                insert: function (args, model, pos, $list) {
                    if (!model) {
                        // 没有提供 App 对象
                        return null;
                    }

                    if (!$list || !$list.length) {
                        // 目标元素列表
                        $list = $notifications;
                    }

                    if (!$$.util.is.int(pos)) {
                        // 添加到列表最后
                        pos = -1;
                    }

                    // 目前位置上当前元素
                    var $next = pos >= 0 ? $list.children('.model-notification').eq(pos) : null,
                        $model = null;

                    if ($next && $next.length) {
                        // 插入到目标元素之前
                        $model = $(_ui.notification.html).insertBefore($next);
                    } else {
                        // 添加到列表最后
                        $model = $(_ui.notification.html).appendTo($list);
                    }

                    // 将对象属性更新到目标元素
                    return _ui.notification.update(args, model, $model, $list).mdcInit();
                },

                /*
                 * 将指定的 App 对象数组添加到指定 DOM 列表的指定位置。
                 * 
                 * @param {any}    args  _api.list 的 args 事件创建的参数。
                 * @param {Object} models 一个 App 对象的数组。
                 * @param {Number} pos   插入位置，非数字将清空现有列表，小于 0 将添加到最后。
                 * @param {jQuery} $list 要插入的 DOM 列表。
                 */
                insertAll: function (args, models, pos, $list) {
                    if (!$list || !$list.length) {
                        // 目标元素列表
                        $list = $notifications;
                    }

                    if (args.pageIndex === '1') {
                        // 清空现有列表
                        $list.empty();
                        // 添加到列表最后
                        pos = -1;
                    }

                    if (models && models.length) {
                        if (pos <= 0) {
                            // 添加到最前或最后
                            models.each(function (model) {
                                _ui.notification.insert(args, model, pos, $list);
                            });
                        } else {
                            // 添加到指定位置
                            models.each(function (model, i) {
                                _ui.notification.insert(args, model, pos + i, $list);
                            });
                        }

                        // 检查应用图标图片是否加载成功，如果不成功，则显示默认的图标
                        $list.find('img.model-notification-sender-face').one('error', function () {
                            this.parentElement.innerHTML = '<i class="material-icons big default-user-face">account_circle</i>';
                        });
                    }

                    return $list;
                },

                /*
                 * 将指定的 App 对象更新到现有的 DOM。
                 * 
                 * @param {any}    args  _api.list 的 args 事件创建的参数。
                 * @param {Object} model  一个 App 对象。
                 * @param {jQuery} $model 现有的 DOM。
                 * @param {jQuery} $list 隶属的 DOM 列表。
                 */
                update: function (args, model, $model, $list) {
                    if (!$list || !$list.length) {
                        // 目标元素列表
                        $list = model ? (model.topTime ? $topNotifications : $notifications) : $notifications;
                    }

                    if (!$model || !$model.length) {
                        // 没有提供 $model 时根据 model 或 args 查找目标元素
                        $model = $list.find('#model-notification-' + model.id);
                    }

                    if (model && $model.length) {
                        var $h = $model
                            .attr('id', 'model-notification-' + model.id)
                            .data('model', model)
                            .children('header'),
                            $face = $h.find('.model-notification-sender-face');

                        if ($face.length < 1) {
                            $h.find('.default-user-face').remove();
                            $face = $('<img class="model-notification-sender-face big" src="' + $$.web.url(model.senderFaceUrl) + '" alt="" />').appendTo($h.children('.pt-row-icon'));
                        } else {
                            $face.attr('src', $$.web.url(model.senderFaceUrl));
                        }

                        $h.find('.model-notification-urgency').text(URGENCY_ICONS[model.urgency])
                            .removeClass('model-notification-urgency-1')
                            .removeClass('model-notification-urgency-2')
                            .removeClass('model-notification-urgency-4')
                            .addClass('model-notification-urgency-' + model.urgency);
                        $h.find('.model-notification-title').text(model.title);
                        $h.find('.model-notification-summary').text(model.summary);
                        $h.find('.model-notification-group').text(model.group);
                        $h.find('.model-notification-sender-name').text(model.senderName);
                        $h.find('.model-notification-receive-time').text($$.util.time.name(model.receiveTime));

                        $model.toggleClass('is-not-read', !!!model.readTime);
                    }

                    return $model;
                },

                /*
                 * 将指定的 App 对象对应的 DOM 元素从列表中移除。
                 * 
                 * @param {any}    args  _api.list 的 args 事件创建的参数。
                 * @param {Object} model  一个 App 对象。
                 * @param {jQuery} $list 要从中移除元素的 DOM 列表。
                 */
                remove: function (args, model, $list) {
                    $('#model-notification-' + args).remove();
                }
            };

            // list 操作事件
            _api.list
                .on('args', function (e) {
                    e.args = {
                        pageIndex: $('#list-page-index').val(), // 页码
                        orderName: $('#list-order-name').val(), // 排序名称
                        orderDirection: $('#list-order-direction').val(), // 排序方向
                        receiveTimeFrom: $('#list-time-from').val(), // 起始日期
                        receiveTimeTo: $('#list-time-to').val(), // 截止日期
                        senderName: $('#list-sender-name').val(), // 发送人
                        title: $('#list-title').val() // 主题
                    };
                })
                .on('success', function (e) {
                    // 置顶通知
                    _ui.notification.insertAll(e.args, e.result.topNotifications, -1, $topNotifications)
                        .toggle(e.result.topNotifications && e.result.topNotifications.length > 0);
                    // 显示列表
                    _ui.notification.insertAll(e.args, e.result.notifications);

                    if (e.args.pageIndex == '1') {
                        $('#loaded-rows').text('0');
                    }

                    // 总行数和已加载行数
                    setLoadedSummary(e.result.notifications.length, e.result.totalRows);
                })
                .on('load', function () {
                    $$.ui.msg = '';
                });

            // 排序方向
            $('.pt-order-field').on('click', function (e) {
                e.preventDefault();

                var
                    // 点击的排序字段
                    $me = $(this),
                    // 排序字段上定义的排序方向
                    dir = ($me.attr('data-order-direction') || 'asc').toLowerCase(),
                    // 排序字段上定义的排序名称，如果没有提供，则按默认排序名称排序
                    name = ($me.attr('data-order-name') || '').toLowerCase();

                // 反转排序方向
                dir = dir == 'asc' ? 'desc' : 'asc';
                // 设置排序方向指示图标
                $me.attr('data-order-direction', dir)
                    .children('.material-icons').text('arrow_drop_' + (dir == 'desc' ? 'up' : 'down'));

                // 设置排序条件
                $('#list-order-name').val(name);
                $('#list-order-direction').val(dir);

                // 重置页码
                $('#list-page-index').val(1);
                // 重新加载列表
                $$.ui.msg = '...';
                _api.list();
            });

            // 加载更多
            $('#load-more').on('click', function () {
                var $pi = $('#list-page-index'),
                    pageIndex = Long.fromValue($pi.val()).add(1);

                $pi.val(pageIndex);

                $$.ui.msg = '...';
                _api.list();
            });

            // 搜索对话框
            $('#search-dialog')
                .on('ok', function (e) {
                    // 重置页码
                    $('#list-page-index').val(1);
                    $$.ui.msg = '...';
                    _api.list();
                    e.done = true;
                });

            // 重置搜索对话框
            $('#reset-search').on('click', function () {
                $('#list-time-from').val('');
                $('#list-time-to').val('');
                $('#list-sender-name').val('');
                $('#list-title').val('');
            });

            // 菜单
            $('#model-notification-menu')
                .on('opening', function (e) {
                    var $item = $(e.items[1]);

                    // 置顶
                    $item.children('i').text(e.model.topTime ? 'vertical_align_bottom' : 'vertical_align_top')
                        .next().text(e.model.topTime ? '取消置顶' : '置顶');

                    // 已读
                    $item = $(e.items[2]);
                    $item.children('i').text(e.model.readTime ? 'visibility_off' : 'visibility')
                        .next().text(e.model.readTime ? '标记为未读' : '标记为已读');
                })
                .on('selected', function (e) {
                    switch (e.selectedIndex) {
                        case 1:
                            // 置顶
                            $$.ui.msg = '...';
                            _api.top
                                .one('args', function (argsEvt) {
                                    argsEvt.args = {
                                        id: e.model.id,
                                        isTop: !!!e.model.topTime
                                    };
                                })
                                .one('success', function (successEvt) {
                                    e.model.topTime = successEvt.args.isTop ? successEvt.result : null;

                                    if (successEvt.args.isTop) {
                                        // 移动到置顶列表中
                                        var $n = $('#model-notification-' + successEvt.args.id).detach(),
                                            $nodes = $topNotifications.children();
                                        if (!$nodes.length) {
                                            $n.appendTo($topNotifications);
                                        } else {
                                            $n.insertBefore($nodes.eq(0));
                                        }

                                        $topNotifications.show();
                                    } else {
                                        // 从置顶列表中移除
                                        var $n = $('#model-notification-' + successEvt.args.id).detach(),
                                            $nodes = $notifications.children();
                                        if (!$nodes.length) {
                                            $n.appendTo($notifications);
                                        } else {
                                            $n.insertBefore($nodes.eq(0));
                                        }

                                        $topNotifications.toggle($topNotifications.children().length > 0);
                                    }
                                })
                                .one('load', function () {
                                    $$.ui.msg = '';
                                })();
                            break;
                        case 2:
                            // 已读或未读
                            $$.ui.msg = '...';
                            _api.read
                                .one('args', function (argsEvt) {
                                    argsEvt.args = {
                                        id: e.model.id,
                                        isRead: !!!e.model.readTime
                                    };
                                })
                                .one('success', function (successEvt) {
                                    e.model.readTime = successEvt.args.isRead ? successEvt.result : null;
                                    _ui.notification.update(successEvt.args, e.model);
                                })
                                .one('load', function () {
                                    $$.ui.msg = '';
                                })();
                            break;
                        case 3:
                            // 删除
                            $$.ui.confirm('确认删除', '您确实要删除通知消息 “' + e.model.title + '” 么？消息被删除后将无法恢复！',
                                function () {
                                    $$.ui.msg = '...';
                                    _api.delete
                                        .one('args', function (argsEvt) {
                                            argsEvt.args = e.model.id;
                                        })
                                        .one('success', function (successEvt) {
                                            _ui.notification.remove(successEvt.args);
                                        })
                                        .one('load', function (loadEvt) {
                                            $$.ui.msg = '';
                                        })();
                                });
                            break;
                        default:
                    }
                });

            $('#details-dialog')
                .on('opening', function (e) {
                    if (!e.model.body) {
                        // 从服务器加载正文
                        $$.ui.msg = '...';
                        _api.details
                            .one('args', function (argsEvt) {
                                argsEvt.args = e.model.id;
                            })
                            .one('success', function (successEvt) {
                                e.model.body = successEvt.result.body;
                                e.model.attachment = successEvt.result.attachment;
                                $('#details-body').text(e.model.body || e.model.summary);
                                if (e.model.attachmentUrl && e.model.attachment) {
                                    $('#details-attachment-name>a')
                                        .text((e.model.attachmentName || e.model.attachmentUrl) + ' (' +
                                        (e.model.attachment.size / 1024).toFixed(2) + ' KB)');
                                }

                                if (!e.model.readTime) {
                                    e.model.readTime = $$.util.time.to(new Date());
                                    _ui.notification.update(successEvt.args, e.model);
                                }
                            })
                            .one('load', function (loadEvt) {
                                $$.ui.msg = '';
                            })();
                    }

                    $('#details-title').val(e.model.title);
                    $('#details-urgency-icon')
                        .removeClass('model-notification-urgency-1')
                        .removeClass('model-notification-urgency-2')
                        .removeClass('model-notification-urgency-4')
                        .addClass('model-notification-urgency-' + e.model.urgency)
                        .text(URGENCY_ICONS[e.model.urgency]);
                    $('#details-urgency-name').val(URGENCY_NAMES[e.model.urgency]);
                    $('#details-sender-name').val(e.model.senderName);
                    $('#details-group').val(e.model.group);
                    $('#details-receive-time').val($$.util.time.name(e.model.receiveTime));

                    if (e.model.attachmentUrl) {
                        if (e.model.attachment) {
                            $('<a href="' + $$.web.url(e.model.attachmentUrl) + '"></a>')
                                .appendTo($('#details-attachment-name').empty())
                                .text((e.model.attachmentName || e.model.attachmentUrl) + ' (' +
                                (e.model.attachment.size / 1024).toFixed(2) + ' KB)')
                                .attr('download', e.model.attachmentName || e.model.attachmentUrl)
                                .attr('title', '下载');
                        } else {
                            $('<a href="' + $$.web.url(e.model.attachmentUrl) + '"></a>')
                                .appendTo($('#details-attachment-name').empty())
                                .text(e.model.attachmentName || e.model.attachmentUrl)
                                .attr('download', e.model.attachmentName || e.model.attachmentUrl)
                                .attr('title', '下载');
                        }
                    } else {
                        $('#details-attachment-name').text('无附件');
                    }
                    $('#details-body').text(e.model.summary);
                });

            // 初始化 mdc
            $main.mdcInit();
        }

        // 加载用户列表
        _api.list();
    });
})(jQuery, pittypat, pittypat.namespace('waln.notifying.inbox'));
